home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 1: Comms & Networking / Almathera Ten on Ten - Disc 1: Comms & Networking.iso / amiga-useful / perl / src / hash.c < prev    next >
C/C++ Source or Header  |  1995-05-04  |  15KB  |  714 lines

  1. /* $RCSfile: hash.c,v $$Revision: 4.0.1.3 $$Date: 92/06/08 13:26:29 $
  2.  *
  3.  *    Copyright (c) 1991, Larry Wall
  4.  *
  5.  *    You may distribute under the terms of either the GNU General Public
  6.  *    License or the Artistic License, as specified in the README file.
  7.  *
  8.  * $Log:    hash.c,v $
  9.  * Revision 4.0.1.3  92/06/08  13:26:29  lwall
  10.  * patch20: removed implicit int declarations on functions
  11.  * patch20: delete could cause %array to give too low a count of buckets filled
  12.  * patch20: hash tables now split only if the memory is available to do so
  13.  * 
  14.  * Revision 4.0.1.2  91/11/05  17:24:13  lwall
  15.  * patch11: saberized perl
  16.  * 
  17.  * Revision 4.0.1.1  91/06/07  11:10:11  lwall
  18.  * patch4: new copyright notice
  19.  * 
  20.  * Revision 4.0  91/03/20  01:22:26  lwall
  21.  * 4.0 baseline.
  22.  * 
  23.  */
  24.  
  25. #include "EXTERN.h"
  26. #include "perl.h"
  27.  
  28. static void hsplit();
  29.  
  30. static char coeff[] = {
  31.         61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
  32.         61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
  33.         61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
  34.         61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
  35.         61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
  36.         61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
  37.         61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
  38.         61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1};
  39.  
  40. static void hfreeentries();
  41.  
  42. STR *
  43. hfetch(tb,key,klen,lval)
  44. register HASH *tb;
  45. char *key;
  46. unsigned int klen;
  47. int lval;
  48. {
  49.     register char *s;
  50.     register int i;
  51.     register int hash;
  52.     register HENT *entry;
  53.     register int maxi;
  54.     STR *str;
  55. #ifdef SOME_DBM
  56.     datum dkey,dcontent;
  57. #endif
  58.  
  59.     if (!tb)
  60.     return &str_undef;
  61.     if (!tb->tbl_array) {
  62.     if (lval) {
  63.         Newz(503,tb->tbl_array, tb->tbl_max + 1, HENT*);
  64.         }
  65.     else
  66.         return &str_undef;
  67.     }
  68.  
  69.     /* The hash function we use on symbols has to be equal to the first
  70.      * character when taken modulo 128, so that str_reset() can be implemented
  71.      * efficiently.  We throw in the second character and the last character
  72.      * (times 128) so that long chains of identifiers starting with the
  73.      * same letter don't have to be strEQ'ed within hfetch(), since it
  74.      * compares hash values before trying strEQ().
  75.      */
  76.     if (!tb->tbl_coeffsize)
  77.     hash = *key + 128 * key[1] + 128 * key[klen-1];    /* assuming klen > 0 */
  78.     else {    /* use normal coefficients */
  79.     if (klen < tb->tbl_coeffsize)
  80.         maxi = klen;
  81.     else
  82.         maxi = tb->tbl_coeffsize;
  83.     for (s=key,        i=0,    hash = 0;
  84.                 i < maxi;            /*SUPPRESS 8*/
  85.          s++,        i++,    hash *= 5) {
  86.         hash += *s * coeff[i];
  87.     }
  88.     }
  89.  
  90.     entry = tb->tbl_array[hash & tb->tbl_max];
  91.     for (; entry; entry = entry->hent_next) {
  92.     if (entry->hent_hash != hash)        /* strings can't be equal */
  93.         continue;
  94.     if (entry->hent_klen != klen)
  95.         continue;
  96.     if (bcmp(entry->hent_key,key,klen))    /* is this it? */
  97.         continue;
  98.     return entry->hent_val;
  99.     }
  100. #ifdef SOME_DBM
  101.     if (tb->tbl_dbm) {
  102.     dkey.dptr = key;
  103.     dkey.dsize = klen;
  104. #ifdef HAS_GDBM
  105.     dcontent = gdbm_fetch(tb->tbl_dbm,dkey);
  106. #else
  107.     dcontent = dbm_fetch(tb->tbl_dbm,dkey);
  108. #endif
  109.     if (dcontent.dptr) {            /* found one */
  110.         str = Str_new(60,dcontent.dsize);
  111.         str_nset(str,dcontent.dptr,dcontent.dsize);
  112.         hstore(tb,key,klen,str,hash);        /* cache it */
  113.         return str;
  114.     }
  115.     }
  116. #endif
  117.     if (lval) {        /* gonna assign to this, so it better be there */
  118.     str = Str_new(61,0);
  119.     hstore(tb,key,klen,str,hash);
  120.     return str;
  121.     }
  122.     return &str_undef;
  123. }
  124.  
  125. bool
  126. hstore(tb,key,klen,val,hash)
  127. register HASH *tb;
  128. char *key;
  129. unsigned int klen;
  130. STR *val;
  131. register int hash;
  132. {
  133.     register char *s;
  134.     register int i;
  135.     register HENT *entry;
  136.     register HENT **oentry;
  137.     register int maxi;
  138.  
  139.     if (!tb)
  140.     return FALSE;
  141.  
  142.     if (hash)
  143.     /*SUPPRESS 530*/
  144.     ;
  145.     else if (!tb->tbl_coeffsize)
  146.     hash = *key + 128 * key[1] + 128 * key[klen-1];
  147.     else {    /* use normal coefficients */
  148.     if (klen < tb->tbl_coeffsize)
  149.         maxi = klen;
  150.     else
  151.         maxi = tb->tbl_coeffsize;
  152.     for (s=key,        i=0,    hash = 0;
  153.                 i < maxi;            /*SUPPRESS 8*/
  154.          s++,        i++,    hash *= 5) {
  155.         hash += *s * coeff[i];
  156.     }
  157.     }
  158.  
  159.     if (!tb->tbl_array)
  160.     Newz(505,tb->tbl_array, tb->tbl_max + 1, HENT*);
  161.  
  162.     oentry = &(tb->tbl_array[hash & tb->tbl_max]);
  163.     i = 1;
  164.  
  165.     for (entry = *oentry; entry; i=0, entry = entry->hent_next) {
  166.     if (entry->hent_hash != hash)        /* strings can't be equal */
  167.         continue;
  168.     if (entry->hent_klen != klen)
  169.         continue;
  170.     if (bcmp(entry->hent_key,key,klen))    /* is this it? */
  171.         continue;
  172.     Safefree(entry->hent_val);
  173.     entry->hent_val = val;
  174.     return TRUE;
  175.     }
  176.     New(501,entry, 1, HENT);
  177.  
  178.     entry->hent_klen = klen;
  179.     entry->hent_key = nsavestr(key,klen);
  180.     entry->hent_val = val;
  181.     entry->hent_hash = hash;
  182.     entry->hent_next = *oentry;
  183.     *oentry = entry;
  184.  
  185.     /* hdbmstore not necessary here because it's called from stabset() */
  186.  
  187.     if (i) {                /* initial entry? */
  188.     tb->tbl_fill++;
  189. #ifdef SOME_DBM
  190.     if (tb->tbl_dbm && tb->tbl_max >= DBM_CACHE_MAX)
  191.         return FALSE;
  192. #endif
  193.     if (tb->tbl_fill > tb->tbl_dosplit)
  194.         hsplit(tb);
  195.     }
  196. #ifdef SOME_DBM
  197.     else if (tb->tbl_dbm) {        /* is this just a cache for dbm file? */
  198.     void hentdelayfree();
  199.  
  200.     entry = tb->tbl_array[hash & tb->tbl_max];
  201.     oentry = &entry->hent_next;
  202.     entry = *oentry;
  203.     while (entry) {    /* trim chain down to 1 entry */
  204.         *oentry = entry->hent_next;
  205.         hentdelayfree(entry);    /* no doubt they'll want this next. */
  206.         entry = *oentry;
  207.     }
  208.     }
  209. #endif
  210.  
  211.     return FALSE;
  212. }
  213.  
  214. STR *
  215. hdelete(tb,key,klen)
  216. register HASH *tb;
  217. char *key;
  218. unsigned int klen;
  219. {
  220.     register char *s;
  221.     register int i;
  222.     register int hash;
  223.     register HENT *entry;
  224.     register HENT **oentry;
  225.     STR *str;
  226.     int maxi;
  227. #ifdef SOME_DBM
  228.     datum dkey;
  229. #endif
  230.  
  231.     if (!tb || !tb->tbl_array)
  232.     return Nullstr;
  233.     if (!tb->tbl_coeffsize)
  234.     hash = *key + 128 * key[1] + 128 * key[klen-1];
  235.     else {    /* use normal coefficients */
  236.     if (klen < tb->tbl_coeffsize)
  237.         maxi = klen;
  238.     else
  239.         maxi = tb->tbl_coeffsize;
  240.     for (s=key,        i=0,    hash = 0;
  241.                 i < maxi;            /*SUPPRESS 8*/
  242.          s++,        i++,    hash *= 5) {
  243.         hash += *s * coeff[i];
  244.     }
  245.     }
  246.  
  247.     oentry = &(tb->tbl_array[hash & tb->tbl_max]);
  248.     entry = *oentry;
  249.     i = 1;
  250.     for (; entry; i=0, oentry = &entry->hent_next, entry = *oentry) {
  251.     if (entry->hent_hash != hash)        /* strings can't be equal */
  252.         continue;
  253.     if (entry->hent_klen != klen)
  254.         continue;
  255.     if (bcmp(entry->hent_key,key,klen))    /* is this it? */
  256.         continue;
  257.     *oentry = entry->hent_next;
  258.     if (i && !*oentry)
  259.         tb->tbl_fill--;
  260.     str = str_mortal(entry->hent_val);
  261.     hentfree(entry);
  262. #ifdef SOME_DBM
  263.       do_dbm_delete:
  264.     if (tb->tbl_dbm) {
  265.         dkey.dptr = key;
  266.         dkey.dsize = klen;
  267. #ifdef HAS_GDBM
  268.         gdbm_delete(tb->tbl_dbm,dkey);
  269. #else
  270.         dbm_delete(tb->tbl_dbm,dkey);
  271. #endif
  272.     }
  273. #endif
  274.     return str;
  275.     }
  276. #ifdef SOME_DBM
  277.     str = Nullstr;
  278.     goto do_dbm_delete;
  279. #else
  280.     return Nullstr;
  281. #endif
  282. }
  283.  
  284. static void
  285. hsplit(tb)
  286. HASH *tb;
  287. {
  288.     int oldsize = tb->tbl_max + 1;
  289.     register int newsize = oldsize * 2;
  290.     register int i;
  291.     register HENT **a;
  292.     register HENT **b;
  293.     register HENT *entry;
  294.     register HENT **oentry;
  295.  
  296.     a = tb->tbl_array;
  297.     nomemok = TRUE;
  298.     Renew(a, newsize, HENT*);
  299.     nomemok = FALSE;
  300.     if (!a) {
  301.     tb->tbl_dosplit = tb->tbl_max + 1;    /* never split again */
  302.     return;
  303.     }
  304.     Zero(&a[oldsize], oldsize, HENT*);        /* zero 2nd half*/
  305.     tb->tbl_max = --newsize;
  306.     tb->tbl_dosplit = tb->tbl_max * FILLPCT / 100;
  307.     tb->tbl_array = a;
  308.  
  309.     for (i=0; i<oldsize; i++,a++) {
  310.     if (!*a)                /* non-existent */
  311.         continue;
  312.     b = a+oldsize;
  313.     for (oentry = a, entry = *a; entry; entry = *oentry) {
  314.         if ((entry->hent_hash & newsize) != i) {
  315.         *oentry = entry->hent_next;
  316.         entry->hent_next = *b;
  317.         if (!*b)
  318.             tb->tbl_fill++;
  319.         *b = entry;
  320.         continue;
  321.         }
  322.         else
  323.         oentry = &entry->hent_next;
  324.     }
  325.     if (!*a)                /* everything moved */
  326.         tb->tbl_fill--;
  327.     }
  328. }
  329.  
  330. HASH *
  331. hnew(lookat)
  332. unsigned int lookat;
  333. {
  334.     register HASH *tb;
  335.  
  336.     Newz(502,tb, 1, HASH);
  337.     if (lookat) {
  338.     tb->tbl_coeffsize = lookat;
  339.     tb->tbl_max = 7;        /* it's a normal associative array */
  340.     tb->tbl_dosplit = tb->tbl_max * FILLPCT / 100;
  341.     }
  342.     else {
  343.     tb->tbl_max = 127;        /* it's a symbol table */
  344.     tb->tbl_dosplit = 128;        /* so never split */
  345.     }
  346.     tb->tbl_fill = 0;
  347. #ifdef SOME_DBM
  348.     tb->tbl_dbm = 0;
  349. #endif
  350.     (void)hiterinit(tb);    /* so each() will start off right */
  351.     return tb;
  352. }
  353.  
  354. void
  355. hentfree(hent)
  356. register HENT *hent;
  357. {
  358.     if (!hent)
  359.     return;
  360.     str_free(hent->hent_val);
  361.     Safefree(hent->hent_key);
  362.     Safefree(hent);
  363. }
  364.  
  365. void
  366. hentdelayfree(hent)
  367. register HENT *hent;
  368. {
  369.     if (!hent)
  370.     return;
  371.     str_2mortal(hent->hent_val);    /* free between statements */
  372.     Safefree(hent->hent_key);
  373.     Safefree(hent);
  374. }
  375.  
  376. void
  377. hclear(tb,dodbm)
  378. register HASH *tb;
  379. int dodbm;
  380. {
  381.     if (!tb)
  382.     return;
  383.     hfreeentries(tb,dodbm);
  384.     tb->tbl_fill = 0;
  385. #ifndef lint
  386.     if (tb->tbl_array)
  387.     (void)memzero((char*)tb->tbl_array, (tb->tbl_max + 1) * sizeof(HENT*));
  388. #endif
  389. }
  390.  
  391. static void
  392. hfreeentries(tb,dodbm)
  393. register HASH *tb;
  394. int dodbm;
  395. {
  396.     register HENT *hent;
  397.     register HENT *ohent = Null(HENT*);
  398. #ifdef SOME_DBM
  399.     datum dkey;
  400.     datum nextdkey;
  401. #ifdef HAS_GDBM
  402.     GDBM_FILE old_dbm;
  403. #else
  404. #ifdef HAS_NDBM
  405.     DBM *old_dbm;
  406. #else
  407.     int old_dbm;
  408. #endif
  409. #endif
  410. #endif
  411.  
  412.     if (!tb || !tb->tbl_array)
  413.     return;
  414. #ifdef SOME_DBM
  415.     if ((old_dbm = tb->tbl_dbm) && dodbm) {
  416. #ifdef HAS_GDBM
  417.     while (dkey = gdbm_firstkey(tb->tbl_dbm), dkey.dptr) {
  418. #else
  419.     while (dkey = dbm_firstkey(tb->tbl_dbm), dkey.dptr) {
  420. #endif
  421.         do {
  422. #ifdef HAS_GDBM
  423.         nextdkey = gdbm_nextkey(tb->tbl_dbm, dkey);
  424. #else
  425. #ifdef HAS_NDBM
  426. #ifdef _CX_UX
  427.         nextdkey = dbm_nextkey(tb->tbl_dbm, dkey);
  428. #else
  429.         nextdkey = dbm_nextkey(tb->tbl_dbm);
  430. #endif
  431. #else
  432.         nextdkey = nextkey(dkey);
  433. #endif
  434. #endif
  435. #ifdef HAS_GDBM
  436.         gdbm_delete(tb->tbl_dbm,dkey);
  437. #else
  438.         dbm_delete(tb->tbl_dbm,dkey);
  439. #endif
  440.         dkey = nextdkey;
  441.         } while (dkey.dptr);    /* one way or another, this works */
  442.     }
  443.     }
  444.     tb->tbl_dbm = 0;            /* now clear just cache */
  445. #endif
  446.     (void)hiterinit(tb);
  447.     /*SUPPRESS 560*/
  448.     while (hent = hiternext(tb)) {    /* concise but not very efficient */
  449.     hentfree(ohent);
  450.     ohent = hent;
  451.     }
  452.     hentfree(ohent);
  453. #ifdef SOME_DBM
  454.     tb->tbl_dbm = old_dbm;
  455. #endif
  456. }
  457.  
  458. void
  459. hfree(tb,dodbm)
  460. register HASH *tb;
  461. int dodbm;
  462. {
  463.     if (!tb)
  464.     return;
  465.     hfreeentries(tb,dodbm);
  466.     Safefree(tb->tbl_array);
  467.     Safefree(tb);
  468. }
  469.  
  470. int
  471. hiterinit(tb)
  472. register HASH *tb;
  473. {
  474.     tb->tbl_riter = -1;
  475.     tb->tbl_eiter = Null(HENT*);
  476.     return tb->tbl_fill;
  477. }
  478.  
  479. HENT *
  480. hiternext(tb)
  481. register HASH *tb;
  482. {
  483.     register HENT *entry;
  484. #ifdef SOME_DBM
  485.     datum key;
  486. #endif
  487.  
  488.     entry = tb->tbl_eiter;
  489. #ifdef SOME_DBM
  490.     if (tb->tbl_dbm) {
  491.     if (entry) {
  492. #ifdef HAS_GDBM
  493.         key.dptr = entry->hent_key;
  494.         key.dsize = entry->hent_klen;
  495.         key = gdbm_nextkey(tb->tbl_dbm, key);
  496. #else
  497. #ifdef HAS_NDBM
  498. #ifdef _CX_UX
  499.         key.dptr = entry->hent_key;
  500.         key.dsize = entry->hent_klen;
  501.         key = dbm_nextkey(tb->tbl_dbm, key);
  502. #else
  503.         key = dbm_nextkey(tb->tbl_dbm);
  504. #endif /* _CX_UX */
  505. #else
  506.         key.dptr = entry->hent_key;
  507.         key.dsize = entry->hent_klen;
  508.         key = nextkey(key);
  509. #endif
  510. #endif
  511.     }
  512.     else {
  513.         Newz(504,entry, 1, HENT);
  514.         tb->tbl_eiter = entry;
  515. #ifdef HAS_GDBM
  516.         key = gdbm_firstkey(tb->tbl_dbm);
  517. #else
  518.         key = dbm_firstkey(tb->tbl_dbm);
  519. #endif
  520.     }
  521.     entry->hent_key = key.dptr;
  522.     entry->hent_klen = key.dsize;
  523.     if (!key.dptr) {
  524.         if (entry->hent_val)
  525.         str_free(entry->hent_val);
  526.         Safefree(entry);
  527.         tb->tbl_eiter = Null(HENT*);
  528.         return Null(HENT*);
  529.     }
  530.     return entry;
  531.     }
  532. #endif
  533.     if (!tb->tbl_array)
  534.     Newz(506,tb->tbl_array, tb->tbl_max + 1, HENT*);
  535.     do {
  536.     if (entry)
  537.         entry = entry->hent_next;
  538.     if (!entry) {
  539.         tb->tbl_riter++;
  540.         if (tb->tbl_riter > tb->tbl_max) {
  541.         tb->tbl_riter = -1;
  542.         break;
  543.         }
  544.         entry = tb->tbl_array[tb->tbl_riter];
  545.     }
  546.     } while (!entry);
  547.  
  548.     tb->tbl_eiter = entry;
  549.     return entry;
  550. }
  551.  
  552. char *
  553. hiterkey(entry,retlen)
  554. register HENT *entry;
  555. int *retlen;
  556. {
  557.     *retlen = entry->hent_klen;
  558.     return entry->hent_key;
  559. }
  560.  
  561. STR *
  562. hiterval(tb,entry)
  563. register HASH *tb;
  564. register HENT *entry;
  565. {
  566. #ifdef SOME_DBM
  567.     datum key, content;
  568.  
  569.     if (tb->tbl_dbm) {
  570.     key.dptr = entry->hent_key;
  571.     key.dsize = entry->hent_klen;
  572. #ifdef HAS_GDBM
  573.     content = gdbm_fetch(tb->tbl_dbm,key);
  574. #else
  575.     content = dbm_fetch(tb->tbl_dbm,key);
  576. #endif
  577.     if (!entry->hent_val)
  578.         entry->hent_val = Str_new(62,0);
  579.     str_nset(entry->hent_val,content.dptr,content.dsize);
  580.     }
  581. #endif
  582.     return entry->hent_val;
  583. }
  584.  
  585. #ifdef SOME_DBM
  586.  
  587. #ifndef O_CREAT
  588. #  ifdef I_FCNTL
  589. #    include <fcntl.h>
  590. #  endif
  591. #  ifdef I_SYS_FILE
  592. #    include <sys/file.h>
  593. #  endif
  594. #endif
  595.  
  596. #ifndef O_RDONLY
  597. #define O_RDONLY 0
  598. #endif
  599. #ifndef O_RDWR
  600. #define O_RDWR 2
  601. #endif
  602. #ifndef O_CREAT
  603. #define O_CREAT 01000
  604. #endif
  605.  
  606. #ifdef HAS_ODBM
  607. static int dbmrefcnt = 0;
  608. #endif
  609.  
  610. bool
  611. hdbmopen(tb,fname,mode)
  612. register HASH *tb;
  613. char *fname;
  614. int mode;
  615. {
  616.     if (!tb)
  617.     return FALSE;
  618. #ifdef HAS_ODBM
  619.     if (tb->tbl_dbm)    /* never really closed it */
  620.     return TRUE;
  621. #endif
  622.     if (tb->tbl_dbm) {
  623.     hdbmclose(tb);
  624.     tb->tbl_dbm = 0;
  625.     }
  626.     hclear(tb, FALSE);    /* clear cache */
  627. #ifdef HAS_GDBM
  628.     if (mode >= 0)
  629.     tb->tbl_dbm = gdbm_open(fname, 0, GDBM_WRCREAT,mode, (void *) NULL);
  630.     if (!tb->tbl_dbm)
  631.     tb->tbl_dbm = gdbm_open(fname, 0, GDBM_WRITER, mode, (void *) NULL);
  632.     if (!tb->tbl_dbm)
  633.     tb->tbl_dbm = gdbm_open(fname, 0, GDBM_READER, mode, (void *) NULL);
  634. #else
  635. #ifdef HAS_NDBM
  636.     if (mode >= 0)
  637.     tb->tbl_dbm = dbm_open(fname, O_RDWR|O_CREAT, mode);
  638.     if (!tb->tbl_dbm)
  639.     tb->tbl_dbm = dbm_open(fname, O_RDWR, mode);
  640.     if (!tb->tbl_dbm)
  641.     tb->tbl_dbm = dbm_open(fname, O_RDONLY, mode);
  642. #else
  643.     if (dbmrefcnt++)
  644.     fatal("Old dbm can only open one database");
  645.     sprintf(buf,"%s.dir",fname);
  646.     if (stat(buf, &statbuf) < 0) {
  647.     if (mode < 0 || close(creat(buf,mode)) < 0)
  648.         return FALSE;
  649.     sprintf(buf,"%s.pag",fname);
  650.     if (close(creat(buf,mode)) < 0)
  651.         return FALSE;
  652.     }
  653.     tb->tbl_dbm = dbminit(fname) >= 0;
  654. #endif
  655. #endif
  656.     if (!tb->tbl_array && tb->tbl_dbm != 0)
  657.     Newz(507,tb->tbl_array, tb->tbl_max + 1, HENT*);
  658.     return tb->tbl_dbm != 0;
  659. }
  660.  
  661. void
  662. hdbmclose(tb)
  663. register HASH *tb;
  664. {
  665.     if (tb && tb->tbl_dbm) {
  666. #ifdef HAS_GDBM
  667.     gdbm_close(tb->tbl_dbm);
  668.     tb->tbl_dbm = 0;
  669. #else
  670. #ifdef HAS_NDBM
  671.     dbm_close(tb->tbl_dbm);
  672.     tb->tbl_dbm = 0;
  673. #else
  674.     /* dbmrefcnt--;  */    /* doesn't work, rats */
  675. #endif
  676. #endif
  677.     }
  678.     else if (dowarn)
  679.     warn("Close on unopened dbm file");
  680. }
  681.  
  682. bool
  683. hdbmstore(tb,key,klen,str)
  684. register HASH *tb;
  685. char *key;
  686. unsigned int klen;
  687. register STR *str;
  688. {
  689.     datum dkey, dcontent;
  690.     int error;
  691.  
  692.     if (!tb || !tb->tbl_dbm)
  693.     return FALSE;
  694.     dkey.dptr = key;
  695.     dkey.dsize = klen;
  696.     dcontent.dptr = str_get(str);
  697.     dcontent.dsize = str->str_cur;
  698. #ifdef HAS_GDBM
  699.     error = gdbm_store(tb->tbl_dbm, dkey, dcontent, GDBM_REPLACE);
  700. #else
  701.     error = dbm_store(tb->tbl_dbm, dkey, dcontent, DBM_REPLACE);
  702. #endif
  703.     if (error) {
  704.     if (errno == EPERM)
  705.         fatal("No write permission to dbm file");
  706.     warn("dbm store returned %d, errno %d, key \"%s\"",error,errno,key);
  707. #ifdef HAS_NDBM
  708.         dbm_clearerr(tb->tbl_dbm);
  709. #endif
  710.     }
  711.     return !error;
  712. }
  713. #endif /* SOME_DBM */
  714.